﻿using CKS.Core.Framework;
using CKS.PLC.Core.Siemens;
using Mapster;
using S7.Net;
using S7.Net.Types;
using SqlSugar.Extensions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using ZR.Model.Models.ProductionControl;

namespace CKS.PLC.Core {

    public class SieminDecoder {

        /// <summary>
        /// 相同DB块内的全部解析数据
        /// </summary>
        public List<DecodeValue> Values { get; set; }


        public SieminDecoder(List<CksPlcDataPosition> points) {
            Points = points;
            Values = new List<DecodeValue>();
            foreach (var point in points) {
                if (point.ParseType.ToLower().Equals("struct"))
                    continue;
                DecodeValue dv = new DecodeValue();
                if (point.ParseType.StartsWith("string"))  //构造时初始化默认值，避免首次运行异常触发
                    dv.Value = dv.OldValue = "";
                else
                    dv.Value = dv.OldValue = (int)0;

                dv.Position = point;

                Values.Add(dv);
            }
        }

        public List<CksPlcDataPosition> Points { get; }

        public List<DecodeValue> Decode(byte[] blockBytes) {
            foreach (var val in Values) {
                var point = val.Position;
                val.Position = point;

                var res = SieminDecoder.SimpleDecode(blockBytes, point.BytePosition, point.ByteLength, point.ParseType);
                val.Value = res.Value;
                val.DecodeObject = res;
            }
            return Values;
        }


        public static DecodeObject SimpleDecode(byte[] bytes, decimal position, int count, string ParseType) {
            DecodeObject obj = new DecodeObject();
            int startIndex = (int)position;
            int bitindex = (int)(position * 10) % 10;
            //ArraySegment<byte> bytes = new ArraySegment<byte>(blockBytes);
            //var buffer = bytes.Slice(startIndex, count).Reverse().ToArray(); //大小端问题，需要反转字节数组
            var lowerType = ParseType.ToLower();
            if (lowerType.IsArrayType(out int arraylenth, out string type2)) {
                //数组暂时只处理 int
                if (type2.IsS7Int16()) {
                    List<short> shorts = new List<short>();

                    try {
                        for (int i = 0; i < arraylenth; i++) {
                            var val = DataConversion.GetInt16DataByBytes(bytes, startIndex);
                            startIndex += 2;  // int16偏移是2字节
                            shorts.Add(val);
                        }
                        obj.Value = shorts;
                    } catch (Exception ex) {

                        throw;
                    }
                } else if (type2.Equals("char")) {
                    try {
                        List<char> shorts = new List<char>();
                        for (int i = 0; i < arraylenth; i++) {
                            var val = DataConversion.GetChar(bytes, startIndex);
                            startIndex += 1;  // 
                            shorts.Add((char)val);
                        }
                        obj.Value = shorts;
                        obj.IsCharArray = true;
                        var charArray = shorts.ToArray();
                        int nullIndex = Array.IndexOf(charArray, '\0');

                        string CharString = nullIndex >= 0
                            ? new string(charArray, 0, nullIndex)  // 截取到\0之前的部分
                            : new string(charArray);  // 没有\0，使用整个数组
                        obj.CharString = CharString.TrimEnd();//去掉末尾空格
                    } catch (Exception ex) {
                        throw;
                    }
                } else if (type2.IsS7Real()) {
                    List<decimal> decimals = new List<decimal>();
                    try {
                        for (int i = 0; i < arraylenth; i++) {

                            var val = DataConversion.GetFloatDataByBytes(bytes, startIndex);
                            startIndex += 4;  // real偏移是4字节
                            decimals.Add((decimal)val);
                        }
                        obj.Value = decimals;
                    } catch (Exception ex) {

                        throw;
                    }
                } else if (type2.Equals("bool")) {
                    List<bool> decimals = new List<bool>();
                    try {

                        for (int i = 0; i < arraylenth; i++) {
                            //bool 需要根据位算出是第几个byte
                            var byteindex = i / 8; // bit 所在的byte位置
                            var boolRealByteIndex = startIndex + byteindex;
                            var bit = i % 8;
                            var val = DataConversion.GetBit(bytes[boolRealByteIndex], bit);

                            decimals.Add(val);
                        }
                        obj.Value = decimals;
                    } catch (Exception ex) {

                        throw;
                    }
                } else if (type2.IsS7String()) {
                    List<string> strings = new List<string>();
                    try {
                        for (int i = 0; i < arraylenth; i++) {
                            int length = 0;
                            if (type2.Contains("string")) {
                                length = Regex.Match(type2, "[0-9]+").Value.ToInt() + 2;
                            }

                            var val = DataConversion.GetStringDataByBytes(bytes, startIndex, length);
                            startIndex += length;  // real偏移是4字节
                            strings.Add(val);
                        }
                        obj.Value = strings;
                    } catch (Exception ex) {

                        throw;
                    }
                }

                if (obj.Value == null)
                    obj.Value = string.Empty; //数组占位暂时不解析
                return obj;
            }

            obj.Value = ParseType.ToLower() switch {
                "char" => DataConversion.GetChar(bytes, startIndex),
                "string" => DataConversion.GetStringDataByBytes(bytes, startIndex, count),
                "int16" => DataConversion.GetInt16DataByBytes(bytes, startIndex),
                "word" => DataConversion.GetWordDataByBytes(bytes, startIndex),
                "int32" => DataConversion.GetInt32DataByBytes(bytes, startIndex),
                "double" => DataConversion.GetDoubleDataByBytes(bytes, startIndex),
                "float" => DataConversion.GetFloatDataByBytes(bytes, startIndex),
                "bool" => DataConversion.GetBit(bytes[startIndex], bitindex),
                "array" => string.Empty,
                "dtl" => DataConversion.GetDTL(bytes, startIndex),
                "dt" => DataConversion.GetDT(bytes, startIndex),
                _ => throw new NotImplementedException("未实现该数据类型的解析")
            };

            return obj;
        }

        public static bool IsArrayType(string ArrayType, out int arrayLenth, out string ParseType) {
            ParseType = "";
            arrayLenth = 0;
            var dataType = ArrayType.ToLower();
            if (dataType.StartsWith("array[") && dataType.Contains("of")) {
                //Array[0..63] of Word

                var matches = Regex.Matches(dataType, "[0-9]+");
                if (matches.Count == 2) {
                    var Start = matches[0].Value.ObjToInt();
                    var End = matches[1].Value.ObjToInt();
                    double sizelenth = End - Start + 1; //数组Length
                    arrayLenth = (int)sizelenth;
                    var arrayType = dataType.Split(' ')[2];
                    ////计算字节Length
                    sizelenth = arrayType switch {
                        "bool" => GetBoolLenth(sizelenth),
                        "int" => sizelenth * 2,
                        "word" => sizelenth * 2,
                        "dword" => sizelenth * 4, //uint
                        "dint" => sizelenth * 4,
                        "real" => sizelenth * 4,
                        "lreal" => sizelenth * 8,
                        _ => sizelenth
                    };
                    ParseType = arrayType;
                    //

                    //
                    return true;
                } else if (matches.Count == 3 && dataType.Contains("of string")) {
                    var arrayType = dataType.Split(' ')[2];
                    ParseType = arrayType;
                    var Start = matches[0].Value.ObjToInt();
                    var End = matches[1].Value.ObjToInt();
                    decimal sizelenth = End - Start + 1;
                    arrayLenth = (int)sizelenth;

                    return true;
                }

            }
            return false;
        }
        private static double GetBoolLenth(double sizelenth) {
            int d = (int)(sizelenth / 8);
            var yu = sizelenth % 8;
            if (yu == 0)
                return d;
            return (double)d + (yu / 10);
        }
    }

    /// <summary>
    /// 解析数据类型
    /// </summary>
    public class DecodeValue {

        /// <summary>
        /// 当前数据的点位
        /// </summary>
        public CksPlcDataPosition Position { get; set; }

        /// <summary>
        /// 读取值
        /// </summary>
        public object Value { get; set; }

        public DecodeObject DecodeObject { get; set; }

        /// <summary>
        /// 读取旧值
        /// </summary>
        public object OldValue { get; set; }

        private bool _isFirstGetChange = true;
        public bool IsChange {
            get {
                if (_isFirstGetChange) {
                    _isFirstGetChange = false;
                    return true;
                }

                try {
                    //通用数组判断值是否发送变化
                    if (this.Position.ParseType.IsArrayType(out int len, out string type2)) {
                        if (Value is Array || Value is System.Collections.IList) {
                            var arr1 = Value.Adapt<List<string>>();
                            var arr2 = OldValue.Adapt<List<string>>();
                            for (int i = 0; i < arr1.Count; i++) {
                                var a = arr1[i];
                                var b = arr2[i];
                                if (a != b)
                                    return true;
                            }
                            return false;
                        }
                    }

                } catch (Exception) {
                    return false;
                }
                //通用数组非判断值是否发送变化
                return !(Value.ToString().Equals(OldValue.ToString()));
            }
        }

        public ISiemensClient SiemensClient { get; set; }

        /// <summary>
        /// 该点位关联的步骤需要操作的数据位置
        /// </summary>
        public List<CksPlcDataPosition> LinkPositions { get; set; }

        /// <summary>
        /// 该订阅点关联数据块的全部点位
        /// 当前点位数据关联的数据源；批量读取数据块的缓存；
        /// </summary>
        public List<DecodeValue> AllValues { get; set; }

        public List<CksPlcDataPosition> AllPositions { get; set; }

        public object GetLinkData(int DataId) {
            try {

                var one = AllValues.Find(a => a.Position.BlockDb == Position.BlockDb && a.Position.LinkActionId == Position.ActionId && a.Position.DataId == DataId);
                return one?.Value;
            } catch (Exception) {
                return null;
            }
        }

        public object GetLinkData(int ActionId, int DataId) {
            try {

                var one = AllValues.Find(a => a.Position.BlockDb == Position.BlockDb && a.Position.LinkActionId == ActionId && a.Position.DataId == DataId);
                return one?.Value;
            } catch (Exception) {
                return null;
            }
        }

        public DecodeObject GetLinkDecodeObject(int DataId) {
            try {

                var one = AllValues.Find(a => a.Position.BlockDb == Position.BlockDb && a.Position.LinkActionId == Position.ActionId && a.Position.DataId == DataId);
                return one?.DecodeObject;
            } catch (Exception) {
                return null;
            }
        }

        public DecodeObject GetLinkDecodeObject(CksPlcDataPosition cksPlcDataPosition) {
            try {
                var one = AllValues.Find(a => a.Position.BlockDb == cksPlcDataPosition.BlockDb && a.Position.Id == cksPlcDataPosition.Id);
                return one?.DecodeObject;
            } catch (Exception) {
                return null;
            }
        }

        public CksPlcDataPosition GetPosition(int db, int action, int dataid = 0) {
            return AllPositions.Find(a => a.BlockDb == db && a.ActionId == action && a.DataId == dataid);
        }


        public CksPlcDataPosition GetReplyPosition(int db, int action, string actionKey = "", int dataid = 0) {
            return AllPositions.Find(a => a.EffectType == 0 && a.BlockDb == db && a.ActionId == action && a.ActionKey == actionKey && a.DataId == dataid);
        }

        /// <summary>
        /// 获取当前点位的解析位置
        /// </summary>
        /// <param name="cksPlcDataPosition">当前触发点位信息</param>
        /// <param name="actionKey">actionKey</param>
        /// <returns></returns>
        public CksPlcDataPosition GetPositionByActionKey(CksPlcDataPosition cksPlcDataPosition, string actionKey) {
            return AllPositions.Where(a => a.PlcId == cksPlcDataPosition.PlcId && a.BlockDb == cksPlcDataPosition.BlockDb && a.ActionKey == actionKey).FirstOrDefault();
        }

        /// <summary>
        /// 获取当前点位的解析位置的回复点位 EffectType=0
        /// </summary>
        /// <param name="cksPlcDataPosition">当前触发点位信息</param>
        /// <param name="actionIdFieldFilter">是否通过actionId字段筛选</param>
        /// <param name="actionKeyFieldFilter">是否通过actionKey字段筛选</param>
        /// <returns></returns>
        public CksPlcDataPosition GetReplyPosition(CksPlcDataPosition cksPlcDataPosition, bool actionIdFieldFilter, bool actionKeyFieldFilter) {
            return GetPosition(cksPlcDataPosition, actionIdFieldFilter, actionKeyFieldFilter).Where(o => o.EffectType == 0).FirstOrDefault();
        }

        /// <summary>
        /// 获取当前点位的解析位置
        /// </summary>
        /// <param name="cksPlcDataPosition">当前触发点位信息</param>
        /// <param name="plcIdFieldFilter">是否通过plcID字段筛选</param>
        /// <param name="blockDbFieldFilter">是否通过blockDb字段筛选</param>
        /// <param name="actionIdFieldFilter">是否通过actionId字段筛选</param>
        /// <param name="actionKeyFieldFilter">是否通过actionKey字段筛选</param>
        /// <param name="dataIdFieldFilter">是否通过dataId字段筛选</param>
        /// <param name="locationIdFieldFilter">是否通过locationId字段筛选</param>
        /// <returns></returns>
        public List<CksPlcDataPosition> GetPosition(CksPlcDataPosition cksPlcDataPosition, bool actionIdFieldFilter = true, bool actionKeyFieldFilter = true, bool plcIdFieldFilter = true, bool blockDbFieldFilter = true, bool dataIdFieldFilter = false, bool locationIdFieldFilter = false) {

            var filteredPositions = AllPositions.AsQueryable();

            if (plcIdFieldFilter) {
                filteredPositions = filteredPositions.Where(p => p.PlcId == cksPlcDataPosition.PlcId);
            }

            if (blockDbFieldFilter) {
                filteredPositions = filteredPositions.Where(p => p.BlockDb == cksPlcDataPosition.BlockDb);
            }

            if (actionIdFieldFilter) {
                filteredPositions = filteredPositions.Where(p => p.ActionId == cksPlcDataPosition.ActionId);
            }

            if (actionKeyFieldFilter) {
                filteredPositions = filteredPositions.Where(p => p.ActionKey == cksPlcDataPosition.ActionKey);
            }

            if (dataIdFieldFilter) {
                filteredPositions = filteredPositions.Where(p => p.DataId == cksPlcDataPosition.DataId);
            }

            if (locationIdFieldFilter) {
                filteredPositions = filteredPositions.Where(p => p.LocationId == cksPlcDataPosition.LocationId);
            }

            return filteredPositions.ToList(); // 返回第一个符合条件的位置，或者null
        }


        public List<DecodeValue> GetActionAllData() {
            try {

                return AllValues.FindAll(a => a.Position.BlockDb == Position.BlockDb && a.Position.LinkActionId == Position.ActionId);

            } catch (Exception) {
                return null;
            }
        }
    }


    public class DecodeObject {

        public object Value { get; set; }

        public bool IsCharArray { get; set; }

        public string CharString { get; set; }

    }

}
